package com.nidu.demo.permission.aop;

import com.nidu.demo.common.enums.DataScopeEnum;
import com.nidu.demo.permission.config.DataPermissionContextHolder;
import com.nidu.demo.permission.service.DataPermissionService;
import com.nidu.demo.security.core.LoginUser;
import com.nidu.demo.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.Set;

/**
 * 数据权限切面
 * 参考租户系统的TenantIgnoreAspect实现
 */
@Aspect
@Slf4j
@RequiredArgsConstructor
public class DataPermissionAspect {

    private final DataPermissionService dataPermissionService;

    @Around("@annotation(dataPermission)")
    public Object around(ProceedingJoinPoint joinPoint, DataPermission dataPermission) throws Throwable {
        // 如果禁用数据权限，直接执行
        if (!dataPermission.enable()) {
            return joinPoint.proceed();
        }

        // 获取当前登录用户
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            log.warn("当前用户未登录，跳过数据权限控制");
            return joinPoint.proceed();
        }

        // 保存旧的上下文
        DataScopeEnum oldDataScope = DataPermissionContextHolder.getDataScope();
        Set<Long> oldDeptIds = DataPermissionContextHolder.getDeptIds();
        Boolean oldIgnore = DataPermissionContextHolder.isIgnore();

        try {
            // 设置数据权限上下文
            setupDataPermissionContext(loginUser);
            
            // 执行业务逻辑
            return joinPoint.proceed();
        } finally {
            // 恢复旧的上下文
            DataPermissionContextHolder.setDataScope(oldDataScope);
            DataPermissionContextHolder.setDeptIds(oldDeptIds);
            DataPermissionContextHolder.setIgnore(oldIgnore);
        }
    }

    /**
     * 设置数据权限上下文
     */
    private void setupDataPermissionContext(LoginUser loginUser) {
        DataScopeEnum dataScope;
        Set<Long> deptIds;

        // 尝试从LoginUser.context获取缓存的数据权限
        dataScope = loginUser.getDataScope();
        deptIds = loginUser.getDeptIds();

        // 如果缓存中没有，则查询数据库并缓存
        if (dataScope == null) {
            log.debug("首次访问，查询用户[{}]的数据权限", loginUser.getId());

            dataScope = dataPermissionService.getUserDataScope(loginUser.getId());
            deptIds = dataPermissionService.getUserAccessibleDeptIds(loginUser.getId(), dataScope);

            // 缓存到LoginUser.context中
            loginUser.setDataPermission(dataScope, deptIds);

            log.debug("缓存用户[{}]数据权限: dataScope={}, deptIds={}",
                    loginUser.getId(), dataScope, deptIds);
        } else {
            log.debug("从缓存获取用户[{}]数据权限: dataScope={}, deptIds={}",
                    loginUser.getId(), dataScope, deptIds);
        }

        // 设置到ThreadLocal上下文供MyBatis拦截器使用
        DataPermissionContextHolder.setDataScope(dataScope);
        DataPermissionContextHolder.setDeptIds(deptIds);
        DataPermissionContextHolder.setIgnore(false);
    }
}